package com.hang.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hang.config.RedisConfig;
import com.hang.entity.*;
import com.hang.exception.MyException;
import com.hang.exception.MyExceptionEnum;
import com.hang.mapper.*;
import com.hang.mapstruct.UserMapStruct;
import com.hang.model.dto.request.ItemDetailDTO;
import com.hang.model.dto.request.ItemPageDTO;
import com.hang.model.dto.request.ItemUserDTO;
import com.hang.model.dto.response.ItemUserQueryListVO;
import com.hang.model.vo.*;
import com.hang.service.IItemUserService;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 */
@Service
@AllArgsConstructor
public class ItemUserServiceImpl extends ServiceImpl<ItemUserMapper, ItemUser>
    implements IItemUserService{
    private RedisConfig redisConfig;

    private UserMapper userMapper;

    private UserMapStruct userMapStruct;

    private ItemMapper itemMapper;

    private ModuleMapper moduleMapper;

    private TbDocumentMapper documentMapper;

    private TbFileMapper fileMapper;

    private TaskMapper taskMapper;

    private BugMapper bugMapper;

    /**
     * 添加项目成员
     * 1. 判断成员是否在项目中，如果是，则不予添加
     * 2. 提供批量添加的功能
     *
     * redis改采用Hash结构的数据结构
     * @param itemUserDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addUser(ItemUserDTO itemUserDTO) {
        RedisTemplate<String, Object> redisTemplate = redisConfig.getRedisTemplateByDb(3);

        Long itemId = itemUserDTO.getItemId();
        String itemName = itemUserDTO.getItemName();
        List<Long> memberIds = itemUserDTO.getMemberSets();

        //将重复的成员去除
        Map<String,Object> map = new HashMap<>();
        map.put("itemId",itemId);
        map.put("memberIds",memberIds);
        List<Long> memberDistinctIds = this.baseMapper.selectDistinctMembers(map);

        //成员ID需要和数据库中的去重
        memberDistinctIds.forEach(
                memberIds::remove
        );

        List<ItemUser> itemUserList = new LinkedList<>();
        memberIds.forEach(
                memberId ->{
                    ItemUser itemUser = new ItemUser();
                    itemUser.setItemId(itemId);
                    itemUser.setItemName(itemName);
                    itemUser.setUserId(memberId);
                    itemUser.setRealName(Optional.ofNullable(userMapper.selectById(memberId)).flatMap(user -> Optional.ofNullable(user.getRealName())).orElse(null));
                    itemUserList.add(itemUser);

                    //Redis操作 : 将成员ID - 项目ID集合插入List中
                    redisTemplate.opsForSet().add(String.valueOf(memberId),itemId);
                }
        );

        //批量插入
        this.saveBatch(itemUserList);

        //添加成员后更新项目人数统计
        updateItemCounts(itemId);
    }

    /**
     * 删除项目成员
     * @param itemUserDTO
     */
    @Override
    @Transactional
    public void deleteUser(ItemUserDTO itemUserDTO) {
        RedisTemplate<String, Object> redisTemplate = redisConfig.getRedisTemplateByDb(3);

        Long itemId = itemUserDTO.getItemId();
        List<Long> memberIds = itemUserDTO.getMemberSets();

        //查询项目中对应的所有成员
        QueryWrapper<ItemUser> itemUserQueryWrapper = new QueryWrapper<>();
        itemUserQueryWrapper
                .lambda()
                .eq(ItemUser::getItemId,itemId)
                .in(ItemUser::getUserId,memberIds);
        List<Long> itemUserIdList = Optional.ofNullable(this.baseMapper.selectList(itemUserQueryWrapper)).orElse(new LinkedList<>()).stream().map(ItemUser::getUserId).collect(Collectors.toList());

        //实现逻辑删除
        this.lambdaUpdate().eq(ItemUser::getItemId,itemId).in(!itemUserIdList.isEmpty(),ItemUser::getUserId,itemUserIdList).remove();


        //删除redis中对应的数据
        memberIds.forEach(
                member ->{
                    if (Boolean.TRUE.equals(redisTemplate.opsForSet().isMember(String.valueOf(member),itemId))) {
                        //如果包含，则移除
                        redisTemplate.opsForSet().remove(String.valueOf(member),itemId);
                    }
                }
        );

        //删除成员后更新人员统计
        updateItemCounts(itemId);
    }

    /**
     * 分页查看成员列表
     * @param itemPageDTO
     * @return
     */
    @Override
    public ItemUserQueryListVO getUserListByItemId(ItemPageDTO itemPageDTO) {
        Long itemId = itemPageDTO.getItemId();
        Integer pageNum = itemPageDTO.getPageNum();
        Integer pageSize = itemPageDTO.getPageSize();

        ItemUserQueryListVO itemUserQueryListVO = new ItemUserQueryListVO();

        QueryWrapper<ItemUser> itemUserQueryWrapper = new QueryWrapper<>();
        itemUserQueryWrapper.lambda().eq(ItemUser::getItemId,itemId);

        Page<ItemUser> page = new Page<>(pageNum,pageSize);
        IPage<ItemUser> iPage = this.baseMapper.selectPage(page,itemUserQueryWrapper);

        List<Long> userIdList = Optional.ofNullable(iPage.getRecords()).orElse(new LinkedList<>()).stream().map(ItemUser::getUserId).collect(Collectors.toList());

        List<User> users = Optional.ofNullable(userMapper.selectBatchIds(userIdList)).orElse(new LinkedList<>());

        //将User转为UserInfo视图
        List<UserInfoVO> userInfoVOList = userMapStruct.usersToUserInfoVOList(users);

        itemUserQueryListVO.setTotal(Optional.ofNullable(this.baseMapper.selectCount(itemUserQueryWrapper)).orElse(0));
        itemUserQueryListVO.setUserInfoVOList(userInfoVOList);

        return itemUserQueryListVO;
    }

    /**
     * 管理员查看项目成员的任务情况
     * @param itemPageDTO
     * @return
     */
    @Override
    public MemberTaskListVO getTaskConditionInItem(ItemPageDTO itemPageDTO) {
        Long itemId = itemPageDTO.getItemId();

        Integer pageNum = itemPageDTO.getPageNum();
        Integer pageSize = itemPageDTO.getPageSize();

        Page<ItemUser> page = new Page<>(pageNum,pageSize);

        //分页查询用户id列表
        List<Long> itemUserIdList = Optional.ofNullable(this.lambdaQuery().eq(ItemUser::getItemId, itemId).page(page).getRecords()).orElse(new LinkedList<>()).stream().map(ItemUser::getUserId).collect(Collectors.toList());

        //获取项目所属的模块集合
        QueryWrapper<Module> moduleQueryWrapper = new QueryWrapper<>();
        moduleQueryWrapper.lambda().eq(Module::getItemId,itemId);

        List<Long> moduleIdList = Optional.ofNullable(moduleMapper.selectList(moduleQueryWrapper)).orElse(new LinkedList<>()).stream().map(Module::getModuleId).collect(Collectors.toList());

        //查看当前用户的项目完成信息
        List<MemberTaskVO> memberTaskVOList = new LinkedList<>();
        itemUserIdList.forEach(
                userId -> {
                    MemberTaskVO memberTaskVO = new MemberTaskVO();
                    memberTaskVO.setMemberId(userId);
                    memberTaskVO.setRealName(Optional.ofNullable(userMapper.selectById(userId).getRealName()).orElse(""));

                    QueryWrapper<TbDocument> documentQueryWrapper = new QueryWrapper<>();
                    documentQueryWrapper.lambda().eq(TbDocument::getUserId,userId).in(TbDocument::getModuleId,moduleIdList);
                    memberTaskVO.setDocumentCount(Optional.ofNullable(documentMapper.selectCount(documentQueryWrapper)).orElse(0));

                    QueryWrapper<TbFile> fileQueryWrapper = new QueryWrapper<>();
                    fileQueryWrapper.lambda().eq(TbFile::getUserId,userId).in(TbFile::getModuleId,moduleIdList);
                    memberTaskVO.setFileCount(Optional.ofNullable(fileMapper.selectCount(fileQueryWrapper)).orElse(0));

                    QueryWrapper<Task> taskQueryWrapper = new QueryWrapper<>();
                    taskQueryWrapper.lambda().eq(Task::getCreateById,userId).eq(Task::getItemId,itemId);
                    memberTaskVO.setTaskCount(Optional.ofNullable(taskMapper.selectCount(taskQueryWrapper)).orElse(0));

                    QueryWrapper<Bug> bugQueryWrapper = new QueryWrapper<>();
                    bugQueryWrapper.lambda().eq(Bug::getCreateById,userId).eq(Bug::getItemId,itemId);
                    memberTaskVO.setBugCount(Optional.ofNullable(bugMapper.selectCount(bugQueryWrapper)).orElse(0));

                    memberTaskVOList.add(memberTaskVO);
                }
        );

        MemberTaskListVO memberTaskListVO = new MemberTaskListVO();
        memberTaskListVO.setTotal(Optional.ofNullable(this.lambdaQuery().eq(ItemUser::getItemId,itemId).count()).orElse(0));
        memberTaskListVO.setMemberTaskVOList(memberTaskVOList);

        return memberTaskListVO;
    }

    /**
     * 管理员查看项目成员的具体任务情况
     * @param itemDetailDTO
     * @return
     */
    @Override
    public MemberTaskDetailVO getTaskDetail(ItemDetailDTO itemDetailDTO) {
        MemberTaskDetailVO memberTaskDetailVO = new MemberTaskDetailVO();

        //基础数据的复制
        BeanUtils.copyProperties(itemDetailDTO,memberTaskDetailVO);

        Long itemId = itemDetailDTO.getItemId();
        Long memberId = itemDetailDTO.getMemberId();

        //扩展属性的附加
        for (int i = 1; i <= 3; i++) {
            packageItemDetail(itemId,memberTaskDetailVO,1,i);
            packageItemDetail(itemId,memberTaskDetailVO,2,i);
        }

        //创建、处理数目
        QueryWrapper<Task> taskQueryWrapper = new QueryWrapper<>();
        taskQueryWrapper.lambda().eq(Task::getItemId,itemId).eq(Task::getCreateById,memberId);
        memberTaskDetailVO.setCreateTaskCount(Optional.ofNullable(taskMapper.selectCount(taskQueryWrapper)).orElse(0));

        taskQueryWrapper.lambda().clear();
        taskQueryWrapper.lambda().eq(Task::getItemId,itemId).eq(Task::getReceiveId,memberId);
        memberTaskDetailVO.setReceiveTaskCount(Optional.ofNullable(taskMapper.selectCount(taskQueryWrapper)).orElse(0));

        //创建、处理故障数目
        QueryWrapper<Bug> bugQueryWrapper = new QueryWrapper<>();
        bugQueryWrapper.lambda().eq(Bug::getItemId,itemId).eq(Bug::getCreateById,memberId);
        memberTaskDetailVO.setCreateBugCount(Optional.ofNullable(bugMapper.selectCount(bugQueryWrapper)).orElse(0));

        bugQueryWrapper.lambda().clear();
        bugQueryWrapper.lambda().eq(Bug::getItemId,itemId).eq(Bug::getReceiveId,memberId);
        memberTaskDetailVO.setReceiveBugCount(Optional.ofNullable(bugMapper.selectCount(bugQueryWrapper)).orElse(0));

        return memberTaskDetailVO;
    }

    /**
     * 项目管理员审批用户申请
     * @param itemId
     * @param userId
     * @param status
     */
    @Override
    public void approval(Long itemId, Long userId, Integer status) {
        if(ObjectUtil.isNull(itemId) || ObjectUtil.isNull(userId)){
            throw new MyException(MyExceptionEnum.ID_IS_NULL);
        }

        RedisTemplate<String, Object> redisTemplate = redisConfig.getRedisTemplateByDb(4);

        if(status == 1){
            //同意用户进入该项目组
            ItemUserDTO itemUserDTO = new ItemUserDTO();

            QueryWrapper<Item> itemQueryWrapper= new QueryWrapper<>();
            itemQueryWrapper.lambda().eq(Item::getItemId,itemId);

            itemUserDTO.setItemId(itemId);
            itemUserDTO.setItemName(itemMapper.selectOne(itemQueryWrapper).getItemName());
            List<Long> memberIds = new LinkedList<>();
            memberIds.add(userId);
            itemUserDTO.setMemberSets(memberIds);

            //复用添加成员接口
            addUser(itemUserDTO);
        }

        String key = String.valueOf(itemId);
        String userIdStr = String.valueOf(userId);

        //删除redis数据
        if (redisTemplate.opsForHash().hasKey(key,userIdStr)) {
            redisTemplate.opsForHash().delete(key,userIdStr);
        }
    }

    //更新项目人数统计
    private void updateItemCounts(Long itemId){
        QueryWrapper<ItemUser> itemUserQueryWrapper = new QueryWrapper<>();
        itemUserQueryWrapper.lambda().eq(ItemUser::getItemId,itemId);

        Integer itemCounts = Optional.ofNullable(this.baseMapper.selectCount(itemUserQueryWrapper)).orElse(0);

        Item item = Optional.ofNullable(itemMapper.selectById(itemId)).orElse(null);
        item.setItemCounts(itemCounts);
        //更新项目人数状态
        itemMapper.updateById(item);
    }

    /**
     * 查找项目任务、缺陷的具体处理情况(策略模式)
     *
     * @param itemId    项目id
     * @param memberTaskDetailVO   细节实体，字段赋予
     * @param method    策略：1未完成的任务 2处理中的任务 3已完成的任务 4未处理的缺陷 5处理中的缺陷 6已处理的缺陷
     */
    private void packageItemDetail(Long itemId, MemberTaskDetailVO memberTaskDetailVO,int type, int method){
        RedisTemplate<String, Object> redisTemplateByTask = redisConfig.getRedisTemplateByDb(1);
        RedisTemplate<String, Object> redisTemplateByBug = redisConfig.getRedisTemplateByDb(2);

        String key = itemId + "-" + method;
        
        if(type == 1){
            int count = Optional.ofNullable(redisTemplateByTask.opsForSet().size(key)).orElse(0L).intValue();
            if(method == 1){
                memberTaskDetailVO.setUnfinishedTaskCount(count);
            }else if(method == 2){
                memberTaskDetailVO.setProcessingTaskCount(count);
            }else if(method == 3){
                memberTaskDetailVO.setCompletedTaskCount(count);
            }
        }else {
            int count = Optional.ofNullable(redisTemplateByBug.opsForSet().size(key)).orElse(0L).intValue();
            if(method == 1){
                memberTaskDetailVO.setUnfinishedBugCount(count);
            }else if(method == 2){
                memberTaskDetailVO.setProcessingBugCount(count);
            }else if(method == 3){
                memberTaskDetailVO.setCompletedBugCount(count);
            }
        }
    }
}